package com.aoip.telemetry.telemetry.configureui.business.computemodel.service.impl;

import com.aoip.telemetry.telemetry.configureui.business.computemodel.mapper.ComputeModelMapper;
import com.aoip.telemetry.telemetry.configureui.business.computemodel.mapper.RelComputeModelStMapper;
import com.aoip.telemetry.telemetry.configureui.business.computemodel.service.ComputeModelService;
import com.aoip.telemetry.telemetry.configureui.common.file.service.FileBaseService;
import com.aoip.telemetry.telemetry.core.redis.RedisCache;
import com.aoip.telemetry.telemetry.core.util.LoadBeanUtil;
import com.aoip.telemetry.telemetry.core.util.ModuleClassLoader;
import com.aoip.telemetry.telemetry.core.util.SpringUtil;
import com.aoip.telemetry.telemetry.entity.constant.TelemetryConstants;
import com.aoip.telemetry.telemetry.entity.enums.CacheKeyEnum;
import com.aoip.telemetry.telemetry.entity.quality.ComputeModelEntity;
import com.aoip.telemetry.telemetry.entity.quality.RelComputeModelStEntity;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.net.MalformedURLException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author chenbai
 * @version 1.0
 * @Description TODO
 * @date 2022/5/1 16:55
 */
@Service
public class ComputeModelServiceImpl implements ComputeModelService {
    @Resource
    private ComputeModelMapper mapper;

    @Resource
    private RelComputeModelStMapper stMapper;
    @Resource
    private LoadBeanUtil beanUtil;
    @Resource
    private FileBaseService fileBaseService;
    @Resource
    private RedisCache redisCache;

    @Override
    public List<ComputeModelEntity> list(ComputeModelEntity entity) {
        QueryWrapper<ComputeModelEntity> queryWrapper = new QueryWrapper<>();
        String modelName = entity.getModelName();
        if (StringUtils.hasText(modelName)) {
            queryWrapper.like(true, "model_name", modelName);
        }
        return mapper.selectList(queryWrapper);
    }

    @Override
    public ComputeModelEntity detail(String id) {
        return mapper.selectById(id);
    }

    @Override
    public List<String> getRelModelStListByModelId(String modelId) {
        QueryWrapper<RelComputeModelStEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(true, "compute_model_id", modelId);
        List<RelComputeModelStEntity> list = stMapper.selectList(queryWrapper);
        List<String> stCodes = new ArrayList<>();
        list.forEach(item -> stCodes.add(item.getStCode()));
        return stCodes;
    }

    @Override
    public int insert(ComputeModelEntity entity) {
        return mapper.insert(entity);
    }

    @Override
    public int insertRelModelSt(List<String> stCodes, String modelId) {
        QueryWrapper<RelComputeModelStEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(true, "compute_model_id", modelId);
        List<RelComputeModelStEntity> list = stMapper.selectList(queryWrapper);
        if (stCodes == null || stCodes.size() < 1) {
            // 若用户去掉勾选所有测站，且数据库中此前已配置部分测站，则应删除这些配置
            if (list != null && list.size() > 0) {
                stMapper.deleteBatchIds(list.stream().map(RelComputeModelStEntity::getId).collect(Collectors.toList()));
            }
            return 1;
        }
        Set<String> insertStCodeSet = new HashSet<>();
        List<String> oldStCodeList = list.stream().map(RelComputeModelStEntity::getStCode).collect(Collectors.toList());
        for (String stCode : stCodes) {
            // 移除之前已存在测站（不需要单独处理），剩下的就是需要删除的测站列表
            boolean exist = oldStCodeList.remove(stCode);
            if (!exist) {
                insertStCodeSet.add(stCode);
            }
        }
        if (oldStCodeList.size() > 0) {
            oldStCodeList.forEach(item -> {
                Map<String, Object> columnMap = new HashMap<>(2);
                columnMap.put("compute_model_id", modelId);
                columnMap.put("st_code", item);
                stMapper.deleteByMap(columnMap);
            });
        }
        if (insertStCodeSet.size() > 0) {
            insertStCodeSet.forEach(stCode -> {
                RelComputeModelStEntity stEntity = new RelComputeModelStEntity();
                stEntity.setStCode(stCode);
                stEntity.setComputeModelId(modelId);
                stMapper.insert(stEntity);
            });
        }
        List<String> relModelStList = getRelModelStListByModelId(modelId);
        redisCache.setCacheList(CacheKeyEnum.REL_COMPUTE_MODEL + ":" + modelId, relModelStList);
        return 1;
    }

    @Override
    public int enableStatusChange(ComputeModelEntity entity) {
        update(entity);
        if (registerBeanToSpring(entity)) {
            return 0;
        }
        return 1;
    }

    private boolean registerBeanToSpring(ComputeModelEntity entity) {
        String modelFileId = entity.getModelFileId();
        String filePath = fileBaseService.getFilePath(modelFileId);
        if (!StringUtils.hasText(filePath)) {
            return true;
        }
        ModuleClassLoader classLoader;
        try {
            classLoader = beanUtil.registerBean(filePath);
        } catch (MalformedURLException e) {
            e.printStackTrace();
            return true;
        }
        classLoader.initBean();
        if (TelemetryConstants.NO_ENABLE == entity.getEnable()) {
            List<String> registeredBean = classLoader.getRegisteredBean();
            registeredBean.forEach(SpringUtil::removeBean);
        }
        return false;
    }

    @Override
    public int update(ComputeModelEntity entity) {
        return mapper.updateById(entity);
    }

    @Override
    public int initCache() {
        List<ComputeModelEntity> list = list(new ComputeModelEntity());
        Collection<String> keys = redisCache.keys(CacheKeyEnum.COMPUTE_MODEL + ":*");
        redisCache.deleteObject(keys);
        Collection<String> relKeys = redisCache.keys(CacheKeyEnum.REL_COMPUTE_MODEL + ":*");
        redisCache.deleteObject(relKeys);
        list.forEach(item -> {
            registerBeanToSpring(item);
            if (TelemetryConstants.ENABLE == item.getEnable()) {
                String modelId = item.getId();
                redisCache.setCacheObject(CacheKeyEnum.COMPUTE_MODEL + ":" + modelId, item);
                List<String> relModelStList = getRelModelStListByModelId(modelId);
                if (relModelStList != null && relModelStList.size() > 0) {
                    redisCache.setCacheList(CacheKeyEnum.REL_COMPUTE_MODEL + ":" + modelId, relModelStList);
                }
            }
        });
        return 1;
    }

    @Override
    public void delete(long[] ids) {
        for (long id : ids) {
            mapper.deleteById(id);
        }
//        mapper.deleteBatchIds(Collections.singletonList(ids));
    }
}
